#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"

using std::cout;
using std::endl;
using std::string;

const int defaultfd = -1;
const string defaultip = "0.0.0.0";
const uint16_t defaultport = 8888;
const int backlog = 10; // 一般不要设置得太大
extern Log lg;


enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError,
};

class ThreadData
{
public:
    ThreadData(int sockfd,const string& ip,uint16_t port,Tcpserver* t)
    :sockfd_(sockfd),clientip_(ip),clientport_(port),tcp_(t)
    {}
public:
    int sockfd_;
    string clientip_;
    uint16_t clientport_;
    Tcpserver* tcp_;
};



class Tcpserver
{
public:
    Tcpserver(const uint16_t &port, const string &ip = defaultip)
        : listensockfd_(defaultfd), port_(port), ip_(ip)
    {
    }

    void InitServer()
    {
        listensockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensockfd_ < 0)
        {
            lg(Fatal, "create listensockfd, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create success, listensockfd: %d", listensockfd_);

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));
        // local.sin_addr.s_addr = INADDR_ANY;

        if (bind(listensockfd_, (struct sockaddr *)&local, sizeof(local)))
        {
            lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }

        lg(Info, "bind success, listensockfd: %d", listensockfd_);

        // Tcp是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种一直等待连接到来的状态
        if (listen(listensockfd_, backlog))
        {
            lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }

        lg(Info, "listen success, listensockfd: %d", listensockfd_);
    }

    void Start()
    {
        ThreadPool<Task>::GetInstance()->Start();
        // signal(SIGCHLD,SIG_IGN);//忽略等待信号
        lg(Info, "tcpServer is running...");
        for (;;)
        {
            // 1.获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensockfd_, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            // 2.根据新连接来进行通信
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);
            // version 1 -- 单进程版
            // Service(sockfd, clientip, clientport);
            // close(sockfd);

            //version 2 -- 多进程版，成本高
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //child
            //     close(listensockfd_);
            //     if(fork() > 0) exit(0);//关掉子进程，将孙子进程交给系统自动回收
            //     Service(sockfd, clientip, clientport); // 孙子进程， systerm领养
            //     close(sockfd);
            //     exit(0);
            // }
            // //father
            // close(sockfd);
            // pid_t rid = waitpid(id,nullptr,0);//子进程关闭时。立即回收，避免阻塞等待

            //version 3 -- 多线程版
            // pthread_t tid;
            // ThreadData* td = new ThreadData(sockfd,clientip,clientport,this);
            // pthread_create(&tid,nullptr,Routine,td);

            //version 4 -- 线程池版
            Task t(sockfd,clientip,clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }

    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->tcp_->Service(td->sockfd_, td->clientip_, td->clientport_);
    //     delete td;
    //     return nullptr;
    // }

    // void Service(int sockfd, const string &clientip, const uint16_t &clientport)
    // {
    //     // 测试代码
    //     char buffer[4096];
    //     while (true)
    //     {
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));
    //         if (n > 0)
    //         {

    //             buffer[n] = 0;
    //             cout << "client say# " << buffer << endl;
    //             string echo_string = "tcpserver echo# ";
    //             echo_string += buffer;

    //             write(sockfd, echo_string.c_str(), echo_string.size());
    //         }
    //         else if (n == 0)
    //         {
    //             lg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         else
    //         {
    //             lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
    //             break;
    //         }
    //     }
    // }

    ~Tcpserver()
    {
    }

private:
    int listensockfd_;
    uint16_t port_;
    string ip_;
};